/*
 * File: YahtzeeBrain.java
 * ------------------
 * This class is responsable of calculate scores 
 * and determining if selected category correspondes to diceRoll
 */
public class YahtzeeBrain implements YahtzeeConstants{
	
	private int[] diceRoll;
	private int category;
	private int[][] numberRepetition;
	private int score=0;
	private int totalScore=0;
	private int lowerScore=0;
	private int upperScore=0;
	private int upperBonus=0;
	
	/**
	 * Initializes a new Yahtzee
	 * @param diceRoll current diceRoll
	 * @param category current selected category
	 */
	public YahtzeeBrain(int[] diceRoll, int category){
		this.diceRoll = diceRoll;
		this.category = category;
		
		setNumberRepetition();
	}	

	/**
	 * Calculates and store how many times a number is repeated
	 * The results are saved in numberRepetition array
	 */
	private void setNumberRepetition(){
		numberRepetition = new int [6][2];
		for (int i=0; i<N_DICE; i++){
			numberRepetition[(diceRoll[i]-1)][1]++;
		}
	}
	
	/////////////////////////////////////////
	//           Getters
	/////////////////////////////////////////
	
	public int getScore(){
		return score;
	}
	
	public int getTotalScore(){
		return totalScore;
	}
	
	public int getLowerScore(){
		return lowerScore;
	}
	
	public int getUpperScore(){
		return upperScore;
	}
	
	public int getUpperBonus(){
		return upperBonus;
	}
	
	/////////////////////////////////////////
	//           Computations
	/////////////////////////////////////////
	
	/**
	 * Calculates the total score for current player
	 * Results are stored in public properties
	 */
	public void calculateTotalScore(int[][] scores, int currentPlayer){
		
		// calculate upper scores and total
		for (int i=ONES; i<=SIXES; i++){
			if (scores[currentPlayer][i]!=-1){
				totalScore += scores[currentPlayer][i];
				upperScore += scores[currentPlayer][i];
			}
		}
		
		// calculate lower scores and total
		for (int i=THREE_OF_A_KIND; i<=CHANCE; i++){
			if (scores[currentPlayer][i]!=-1){
				totalScore += scores[currentPlayer][i];
				lowerScore += scores[currentPlayer][i];
			}
		}
	}
	
	/**
	 * Calculates the upper bonus
	 * Results are stored in upperBonus property
	 */
	public void calculateUpperBonus(){
		if (upperScore>63){
			upperBonus=35;
			totalScore = totalScore + upperBonus;
		}
	}
	
	/**
	 * Sums all the dices
	 * Resuls are stored in score public property
	 */
	private void sumAllDices(){
		for(int i=0; i<diceRoll.length; i++){
			score+= diceRoll[i];
		}
	}
	
	/**
	 * Sums dices with dice number
	 * Results are stored in score public property
	 * @param dice sum dices with this number
	 */
	private void sumAllDicesEqualTo(int dice){
		int sum =0;

		for (int i =0; i<diceRoll.length; i++){
			if (diceRoll[i]==dice){
				sum += diceRoll[i];
			}
		}
		
		score = sum;
	}
	
	
	/////////////////////////////////////////
	//           Category Check
	/////////////////////////////////////////
	
	public boolean isSimple(){
		if (category==CHANCE){
			sumAllDices();
		}else{
			sumAllDicesEqualTo(category+1);
		}
		
		return category >= ONES && category <= SIXES || category == CHANCE;
	}
	
	/**
	 * Check if the category corresponds to a certain kind
	 * @param kind can be THREE_OF_A_KIND, FOUR_OF_A_KIND or YAHTZEE
	 * @return
	 */
	private boolean isOfAKind(int kind){
		boolean found = false;
		
		for (int i=0; i<=diceRoll.length; i++){
			if (numberRepetition[i][1] >= kind){
				found = true;
				sumAllDices();
			}
		}

		return found;
	}
	
	public boolean isThreeOfAKind(){
		if (category==THREE_OF_A_KIND){
			return isOfAKind(3);
		}
		
		return false;
	}
	
	public boolean isFourOfAKind(){
		if (category==FOUR_OF_A_KIND){
			return isOfAKind(4);
		}
		
		return false;
	}
	
	public boolean isYahtzee(){
		if (category==YAHTZEE){
			score = 50;
			
			return isOfAKind(5);
		}
		
		return false;
	}
	
	public boolean isFullHouse(){
		if (category==FULL_HOUSE){
		
			boolean foundThrees = false;
			boolean foundTwos = false;
			
			for (int i=0; i<=diceRoll.length; i++){
				if (numberRepetition[i][1] == 3){
					foundThrees = true;
				}
				if (numberRepetition[i][1] == 2){
					foundTwos = true;
				}
			}

			score = 25;
			
			return foundThrees && foundTwos;
		}		
		
		return false;
	}
	
	public boolean isLargeStraight(){
		if (category==LARGE_STRAIGHT){
			score = 40;
			
			return checkStraight(0, 4) || checkStraight(1, 5);
		}
		
		return false;
	}
	
	public boolean isSmallStraight(){
		if (category==SMALL_STRAIGHT){
			score = 30;
			
			return checkStraight(0, 3) 
				|| checkStraight(1, 4)
				|| checkStraight(2, 5);
		}
		
		return false;
	}	
	
	/**
	 * Checks if the numberRepetition corresponds to a straight
	 * @param start begining of straight 
	 * @param end end of straight
	 * @return
	 */
	private boolean checkStraight(int start, int end){
		boolean isStraight = true;
		
		for (int i=start; i<end; i++)
		{
			isStraight &= numberRepetition[i][1]==1; 
		}
		
		return isStraight;
	}
}
